<template>
  <div class="three-box"></div>
</template>

<script setup>
import {
  Scene,
  WebGLRenderer,
  PerspectiveCamera,
  BoxGeometry,
  MeshStandardMaterial,
  Mesh,
  AxesHelper,
  SpotLight,
  SphereGeometry,
  Color,
  PlaneGeometry,
  MeshLambertMaterial,
  PCFSoftShadowMap
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { onMounted } from "vue";

onMounted(() => {
  // 创建场景
  let scene = new Scene();
  // 设置摄像机
  let camera = new PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    2000
  );
  // 创建渲染器
  let renderer = new WebGLRenderer();
  // 设置渲染器的初始颜色
  renderer.setClearColor(new Color(0xeeeeee));
  // 设置输出canvas画面的大小
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染物体阴影

  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = PCFSoftShadowMap;
  // renderer.shadowMapEnabled = true;
  // 显示三维坐标系
  let axes = new AxesHelper(20);

  // 添加坐标系到场景中
  scene.add(axes);
  // 创建地面的几何体
  let planeGeometry = new PlaneGeometry(60, 20);
  // 给地面物体上色
  // let planeMaterial = new MeshBasicMaterial({ color: 0xcccccc });
  let planeMaterial = new MeshStandardMaterial({ color: 0xcccccc });
  // 创建地面
  let plane = new Mesh(planeGeometry, planeMaterial);
  // 物体移动位置
  // plane.rotation.x = -0.5 * Math.PI;
  // plane.position.x = 15;
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 0;
  plane.position.y = 0;
  plane.position.z = 0;
  plane.castShadow = true;
  // 接收阴影
  plane.receiveShadow = true;

  // 将地面添加到场景中
  scene.add(plane);

  // 添加立方体
  let cubeGeometry = new BoxGeometry(4, 4, 4);
  let cubeMaterial = new MeshLambertMaterial({ color: 0xff0000 });
  let cube = new Mesh(cubeGeometry, cubeMaterial);

  cube.position.x = 0;
  cube.position.y = 4;
  cube.position.z = 2;
  // 对象是否渲染到阴影贴图当中
  cube.castShadow = true;
  cube.receiveShadow = true;

  scene.add(cube);

  // 球体
  let sphereGeometry = new SphereGeometry(4, 20, 20);
  let spherMaterial = new MeshLambertMaterial({ color: 0xff0000 });
  let sphere = new Mesh(sphereGeometry, spherMaterial);
  sphere.position.x = 10;
  sphere.position.y = 4;
  sphere.position.z = 0;
  // 对象是否渲染到阴影贴图当中
  sphere.castShadow = true;

  scene.add(sphere);

  // 创建聚光灯
  let spotLight = new SpotLight(0xffffff);
  spotLight.position.set(130, 130, 130);

  spotLight.angle = Math.PI / 4; // 聚光灯的扩散范围，最大为Math.PI / 2
  spotLight.penumbra = 0.05; // 由于半影而衰减的聚光锥的百分比。取值介于0和1之间。默认值为零
  spotLight.decay = 2; // 光线沿光线距离变暗的量, 可理解为衰减速率
  spotLight.distance = 1000; // 最大范围的光

  spotLight.castShadow = true; // 将光源能产生阴影的属性设置为true
  spotLight.shadow.mapSize.width = 1024; // 定义阴影贴图的宽度和高度,必须为2的整数此幂
  spotLight.shadow.mapSize.height = 1024; // 较高的值会以计算时间为代价提供更好的阴影质量
  spotLight.shadow.camera.near = 100; // 光源在世界坐标内的视角，物体的位置必须大于此最小值才能产生阴影
  spotLight.shadow.camera.far = 140;
  spotLight.target = sphere;
  // 添加聚光灯
  scene.add(spotLight);

  // 定位相机，并且指向场景中心
  camera.position.x = 30;
  camera.position.y = 30;
  camera.position.z = 30;
  camera.lookAt(scene.position);

  // 将渲染器输出添加html元素中
  document.querySelector(".three-box").appendChild(renderer.domElement);
  renderer.render(scene, camera);

  let controls = new OrbitControls(camera, renderer.domElement); //创建控件对象

  function animate() {
    requestAnimationFrame(animate);

    // cube.rotation.x += 0.01;
    // cube.rotation.y += 0.01;
    controls.update();

    renderer.render(scene, camera);
  }

  animate();
});
</script>

<style lang="less" scoped>
.three-box {
  width: 100%;
  height: 100vh;
}
</style>
